﻿ #region Disclaimer/Info
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //   File:		StringExtensions.cs
 //   Website:		http://dexterblogengine.com/
 //   Authors:		http://dexterblogengine.com/About.ashx
 //   Rev:		1
 //   Created:		19/01/2011
 //   Last edit:		19/01/2011
 //   License:		GNU Library General Public License (LGPL)
 //   File:            StringExtensions.cs
 //   For updated news and information please visit http://dexterblogengine.com/
 //   Dexter is hosted to Codeplex at http://dexterblogengine.codeplex.com
 //   For any question contact info@dexterblogengine.com
 //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 #endregion
 
namespace System
{
	#region Usings

	using System.IO;
	using System.Linq;
	using System.Security.Cryptography;
	using System.Text;
	using System.Text.RegularExpressions;
	using System.Web;
	using System.Xml.Serialization;

	#endregion

	/// <summary>
	/// 	Adds behaviors to the <c>String</c> class.
	/// </summary>
	public static class StringExtensions
	{
		/// <summary>
		/// 	Appends the specified value.
		/// </summary>
		/// <param name = "value">The value.</param>
		/// <param name = "valueToAppend">The value to append.</param>
		/// <returns></returns>
		public static string Append ( this String value , string valueToAppend )
		{
			if ( String.IsNullOrEmpty ( value ) )
				return valueToAppend;

			if ( string.IsNullOrEmpty ( valueToAppend ) )
				return value;

			return Append ( value , new[] {valueToAppend} );
		}

		/// <summary>
		/// 	Appends the specified value.
		/// </summary>
		/// <param name = "value">The value.</param>
		/// <param name = "valuesToAppend">The values to append.</param>
		/// <returns></returns>
		public static string Append ( this String value , params object[] valuesToAppend )
		{
			if ( value == null && ( valuesToAppend == null || valuesToAppend.Length == 0 ) )
				return null;

			StringBuilder sb = new StringBuilder ( value );

			foreach ( object s in valuesToAppend )
			{
				if ( s == null )
					continue;

				sb.Append ( s );
			}

			return sb.ToString ();
		}

		/// <summary>
		/// 	Performs a Like compare using the specified compare pattern.
		/// </summary>
		/// <param name = "value">The source value to compare against the pattern.</param>
		/// <param name = "pattern">The pattern to use a a search pattern.</param>
		/// <returns><c>True</c> in case of successful match, otherwise <c>false</c>.</returns>
		/// <remarks>
		/// 	The default IsLike is performed using a case insensitive search.
		/// </remarks>
		public static Boolean IsLike ( this String value , String pattern )
		{
			return IsLike ( value , pattern , true );
		}

		/// <summary>
		/// 	Performs a Like compare using the specified compare patterns, using an or logic, 
		/// 	the first succesfull match blocks the comparison.
		/// </summary>
		/// <param name = "value">The source value to compare against the pattern.</param>
		/// <param name = "patterns">The patterns to match.</param>
		/// <returns>
		/// 	<c>True</c> in case of successful match, otherwise <c>false</c>.
		/// </returns>
		/// <remarks>
		/// 	The default IsLike is performed using a case insensitive search.
		/// </remarks>
		public static Boolean IsLike ( this String value , params String[] patterns )
		{
			return patterns.Any ( pattern => value.IsLike ( pattern ) );
		}

		/// <summary>
		/// 	Performs a Like compare using the specified compare pattern.
		/// </summary>
		/// <param name = "value">The source value to compare against the pattern.</param>
		/// <param name = "pattern">The pattern to use a a search pattern.</param>
		/// <param name = "ignoreCase"><c>True</c> to perform a case insensitive search, otherwise <c>false</c>.</param>
		/// <returns>
		/// 	<c>True</c> in cas of successful match, otherwise <c>false</c>.
		/// </returns>
		public static Boolean IsLike ( this String value , String pattern , Boolean ignoreCase )
		{
			/*
			 * Se nella stringa ci sono delle '\' dobbiamo 
			 * metterci un bell'escape
			 */
			pattern = pattern.Replace ( @"\" , @"\\" );

			/*
			 * Se nella stringa ci sono dei '.' dobbiamo 
			 * metterci un bell'escape, questa operazione
			 * � da fare dopo la precedente per evitare
			 * di raddoppiare anche queste \
			 */
			pattern = pattern.Replace ( "." , "\\." );

			/*
			 * Gli '*' vengono sostituiti con '.*'
			 */
			pattern = pattern.Replace ( "*" , ".*" );

			/*
			 * I '?' vengono sostituiti con il semplice '.'
			 */
			pattern = pattern.Replace ( "?" , "." );

			/*
			 * Includiamo il nostro pattern tra
			 * \A e \z per fare in modo che matchi con
			 * l'inizio e la fine della stringa altrimenti
			 * ad es. Beatrice matcha con B*r 
			 */
			pattern = String.Concat ( "\\A" , pattern , "\\z" );

			RegexOptions options = RegexOptions.None;
			if ( ignoreCase )
				options |= RegexOptions.IgnoreCase;

			bool match = Regex.Match ( value , pattern , options ).Success;

			return match;
		}

		/// <summary>
		/// 	Determines whether the specified string is null or empty.
		/// </summary>
		/// <param name = "value">The string to test.</param>
		/// <returns>
		/// 	<c>true</c> if the specified string is null or empty; otherwise, <c>false</c>.
		/// </returns>
		public static Boolean IsNullOrEmpty ( this String value )
		{
			return String.IsNullOrEmpty ( value );
		}

		/// <summary>
		/// 	Determines if the given string is a number.
		/// </summary>
		/// <param name = "value">The string to analyze.</param>
		/// <returns><c>true</c> if the given string represents a number; otherwise <c>false</c>.</returns>
		public static Boolean IsNumber ( this String value )
		{
			if ( String.IsNullOrEmpty ( value ) )
				return false;

			return value.All ( Char.IsNumber );
		}

		///<summary>
		///	Convert a serialized string to a concrete class
		///</summary>
		///<param name = "xml"></param>
		///<typeparam name = "T"></typeparam>
		///<returns></returns>
		public static T Deserialize< T > ( this string xml )
		{
			XmlSerializer s = new XmlSerializer ( typeof ( T ) );
			using ( TextReader r = new StringReader ( xml ) )
			{
				return ( T ) s.Deserialize ( r );
			}
		}

		/// <summary>
		/// 	Capitalizes the specified string. (es: <c>imperugo</c> will be <c>Imperugo</c>)
		/// </summary>
		/// <param name = "value">The value.</param>
		/// <returns></returns>
		public static string Capitalize ( this string value )
		{
			if ( String.IsNullOrEmpty ( value ) )
				return value;

			return ( value.Substring ( 0 , 1 ).ToUpper () + ( ( value.Length > 1 )
			                                                  	? value.Substring ( 1 )
			                                                  	: string.Empty ) );
		}

		/// <summary>
		/// 	Lefts the specified s.
		/// </summary>
		/// <param name = "s">The s.</param>
		/// <param name = "length">The length.</param>
		/// <returns></returns>
		public static string Left ( this string s , int length )
		{
			if ( s == null )
				return null;

			if ( length < 0 )
				throw new ArgumentOutOfRangeException ( "length" );

			if ( ( length == 0 ) || string.IsNullOrEmpty ( s ) )
				return string.Empty;

			if ( length <= s.Length )
				return s.Substring ( 0 , length );

			return s;
		}

		/// <summary>
		/// 	Rights the specified s.
		/// </summary>
		/// <param name = "s">The s.</param>
		/// <param name = "length">The length.</param>
		/// <returns></returns>
		public static string Right ( this string s , int length )
		{
			if ( length < 0 )
				throw new ArgumentOutOfRangeException ( "length" );

			if ( ( length == 0 ) || string.IsNullOrEmpty ( s ) )
				return string.Empty;

			if ( length <= s.Length )
				return s.Substring ( s.Length - length , length );

			return s;
		}

		/// <summary>
		/// 	Splits the specified s.
		/// </summary>
		/// <param name = "s">The s.</param>
		/// <param name = "separator">The separator.</param>
		/// <returns></returns>
		public static string[] Split ( this string s , string separator )
		{
			return s.Split ( separator.ToCharArray () );
		}

		/// <summary>
		/// 	Cuts the specified text.
		/// </summary>
		/// <param name = "s">The text.</param>
		/// <param name = "lenght">The lenght.</param>
		/// <returns>The cutted string</returns>
		public static string Cut ( this string s , int lenght )
		{
			return Cut ( s , lenght , string.Empty );
		}

		/// <summary>
		/// 	Cuts the specified text.
		/// </summary>
		/// <param name = "text">The text.</param>
		/// <param name = "lenght">The lenght.</param>
		/// <param name = "finalText">The final text.</param>
		/// <returns>The cutted string</returns>
		public static string Cut ( this string text , int lenght , string finalText )
		{
			if ( string.IsNullOrEmpty ( text ) )
				return text;

			if ( lenght > text.Length )
				return text;

			finalText = finalText ?? string.Empty;

			string returnValue = text.Substring ( 0 , lenght );

			return string.IsNullOrEmpty ( finalText )
			       	? returnValue
			       	: string.Concat ( returnValue , finalText );
		}

		/// <summary>
		/// 	Toes the int32.
		/// </summary>
		/// <param name = "s">The s.</param>
		/// <returns></returns>
		public static int ToInt32 ( this string s )
		{
			return int.Parse ( s );
		}

		/// <summary>
		/// 	Toes the int32.
		/// </summary>
		/// <param name = "s">The s.</param>
		/// <param name = "defaultValue">The default value.</param>
		/// <returns></returns>
		public static int ToInt32 ( this string s , int defaultValue )
		{
			int num;

			if ( !int.TryParse ( s , out num ) )
				return defaultValue;

			return num;
		}

		/// <summary>
		/// 	Toes the int32.
		/// </summary>
		/// <param name = "s">The s.</param>
		/// <returns></returns>
		public static long ToInt64(this string s)
		{
			return long.Parse(s);
		}

		/// <summary>
		/// 	Toes the int32.
		/// </summary>
		/// <param name = "s">The s.</param>
		/// <param name = "defaultValue">The default value.</param>
		/// <returns></returns>
		public static long ToInt64(this string s, long defaultValue)
		{
			long num;

			if (!long.TryParse(s, out num))
				return defaultValue;

			return num;
		}

		/// <summary>
		/// 	Removes the HTML comment.
		/// </summary>
		/// <param name = "text">The text.</param>
		/// <returns></returns>
		public static string RemoveHtmlComment ( this string text )
		{
			return Regex.Replace ( text , @"<!--((?!-->).|\r|\n)*-->" , String.Empty );
		}

		/// <summary>
		/// 	Cleans the text.
		/// </summary>
		/// <param name = "text">The text.</param>
		/// <returns></returns>
		public static string CleanHtmlText ( this string text )
		{
			text = Regex.Replace ( text , "<[^>]*>" , String.Empty );
			text = Regex.Replace ( text , "<script[^>]*>" , String.Empty , RegexOptions.IgnoreCase );
			text = Regex.Replace ( text , "javascript:" , string.Empty , RegexOptions.IgnoreCase );

			return text;
		}

		/// <summary>
		/// 	Toes the date time.
		/// </summary>
		/// <param name = "s">The s.</param>
		/// <returns></returns>
		public static DateTime ToDateTime ( this string s )
		{
			return Convert.ToDateTime ( s );
		}

		///<summary>
		///</summary>
		///<param name = "s"></param>
		///<param name = "defaultValue"></param>
		///<returns></returns>
		public static DateTime ToDateTime ( this string s , DateTime defaultValue )
		{
			DateTime v1;

			if ( !DateTime.TryParse ( s , out v1 ) )
				return defaultValue;

			return v1;
		}

		/// <summary>
		/// 	Toes the boolean.
		/// </summary>
		/// <param name = "text">The text.</param>
		/// <returns></returns>
		public static bool ToBoolean ( this string text )
		{
			return Convert.ToBoolean ( text );
		}

		/// <summary>
		/// 	Toes the boolean.
		/// </summary>
		/// <param name = "text">The text.</param>
		/// <param name = "defaultValue">if set to <c>true</c> [default value].</param>
		/// <returns></returns>
		public static bool ToBoolean ( this string text , bool defaultValue )
		{
			bool value;

			if ( !bool.TryParse ( text , out value ) )
				return defaultValue;

			return value;
		}

		/// <summary>
		/// Toes the float.
		/// </summary>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		public static float ToFloat ( this string text ) {
			return Convert.ToSingle ( text );
		}

		/// <summary>
		/// Toes the float.
		/// </summary>
		/// <param name="text">The text.</param>
		/// <param name="defaultValue">if set to <c>true</c> [default value].</param>
		/// <returns></returns>
		public static float ToFloat ( this string text, float defaultValue ) {
			float value;

			if (!float.TryParse ( text, out value ))
				return defaultValue;

			return value;
		}

		/// <summary>
		/// 	Hash a string with MD5 Algorithm
		/// </summary>
		/// <param name = "text">The text.</param>
		/// <returns></returns>
		public static string ToMd5 ( this string text )
		{
			if ( text.IsNullOrEmpty () )
				throw new ArgumentNullException ( "text" );

			MD5 md5Hasher = MD5.Create ();

			byte[] data = md5Hasher.ComputeHash ( Encoding.Default.GetBytes ( text ) );

			StringBuilder sBuilder = new StringBuilder ();

			for ( int i = 0; i < data.Length; i++ )
				sBuilder.Append ( data [ i ].ToString ( "x2" ) );

			return sBuilder.ToString ();
		}

		/// <summary>
		/// 	Extracts the text block.
		/// </summary>
		/// <param name = "source">The source.</param>
		/// <param name = "blockId">The block id.</param>
		/// <returns></returns>
		public static string ExtractTextBlock ( this string source , string blockId )
		{
			string blockBegin = string.Format ( "[{0}-BEGIN]" , blockId );
			string blockEnd = string.Format ( "[{0}-END]" , blockId );

			int beginAt = source.IndexOf ( blockBegin , 0 , StringComparison.InvariantCultureIgnoreCase );
			if ( beginAt != -1 )
			{
				int firstValidCharAt = beginAt + blockBegin.Length;
				int endsAt = source.IndexOf ( blockEnd , firstValidCharAt , StringComparison.InvariantCultureIgnoreCase );
				if ( endsAt != -1 )
					return source.Substring ( firstValidCharAt , endsAt - firstValidCharAt );
			}

			return null;
		}

		/// <summary>
		/// 	Makes the name of the valid file.
		/// </summary>
		/// <param name = "name">The name.</param>
		/// <returns></returns>
		public static string MakeValidFileName ( this string name )
		{
			if ( String.IsNullOrEmpty ( name ) )
				throw new ArgumentOutOfRangeException ( "name" , "MakeValidFileName does not work with null string" );
			string invalidChars = Regex.Escape ( new string ( Path.GetInvalidFileNameChars () ) );
			string invalidReStr = string.Format ( @"[{0}]" , invalidChars );
			return Regex.Replace ( name , invalidReStr , "_" );
		}

		/// <summary>
		/// 	Encodes the HTML.
		/// </summary>
		/// <param name = "value">The value.</param>
		/// <returns></returns>
		public static string EncodeHtml ( this string value )
		{
			if ( value.IsNullOrEmpty () )
				return value;

			return HttpUtility.HtmlEncode ( value );
		}

		/// <summary>
		/// 	Encodes the HTML.
		/// </summary>
		/// <param name = "value">The value.</param>
		/// <returns></returns>
		public static string DecodeHtml ( this string value )
		{
			if ( value.IsNullOrEmpty () )
				return value;

			return HttpUtility.HtmlDecode ( value );
		}

		/// <summary>
		/// 	HTMLs the attribute encode.
		/// </summary>
		/// <param name = "value">The value.</param>
		/// <returns></returns>
		public static string EncodeHtmlAttribute ( this string value )
		{
			if ( value.IsNullOrEmpty () )
				return value;

			return HttpUtility.HtmlAttributeEncode ( value );
		}

		/// <summary>
		/// 	URLs the encode.
		/// </summary>
		/// <param name = "value">The value.</param>
		/// <returns></returns>
		public static string EncodeUrl ( this string value )
		{
			if ( value.IsNullOrEmpty () )
				return value;

			return HttpUtility.UrlPathEncode ( value );
		}

		/// <summary>
		/// 	URLs the decode.
		/// </summary>
		/// <param name = "value">The value.</param>
		/// <returns></returns>
		public static string DecodeUrl ( this string value )
		{
			if ( value.IsNullOrEmpty () )
				return value;

			return HttpUtility.UrlDecode ( value );
		}

		/// <summary>
		/// 	Encrypt a byte array into a byte array using a key and an IV
		/// </summary>
		/// <param name = "clearData">The clear data.</param>
		/// <param name = "key">The key.</param>
		/// <param name = "iv">The iv.</param>
		/// <returns></returns>
		public static byte[] Encrypt ( this byte[] clearData, byte[] key, byte[] iv ) {
			// Create a MemoryStream that is going to accept the encrypted bytes
			MemoryStream ms = new MemoryStream ( );

			// Create a symmetric algorithm.
			// We are going to use Rijndael because it is strong and available on all platforms.
			// You can use other algorithms, to do so substitute the next line with something like
			//                      TripleDES alg = TripleDES.Create();
			Rijndael alg = Rijndael.Create ( );

			// Now set the key and the IV.
			// We need the IV (Initialization Vector) because the algorithm is operating in its default
			// mode called CBC (Cipher Block Chaining). The IV is XORed with the first block (8 byte)
			// of the data before it is encrypted, and then each encrypted block is XORed with the
			// following block of plaintext. This is done to make encryption more secure.
			// There is also a mode called ECB which does not need an IV, but it is much less secure.
			alg.Key = key;
			alg.IV = iv;

			// Create a CryptoStream through which we are going to be pumping our data.
			// CryptoStreamMode.Write means that we are going to be writing data to the stream
			// and the output will be written in the MemoryStream we have provided.
			CryptoStream cs = new CryptoStream ( ms, alg.CreateEncryptor ( ), CryptoStreamMode.Write );

			// Write the data and make it do the encryption
			cs.Write ( clearData, 0, clearData.Length );

			// Close the crypto stream (or do FlushFinalBlock).
			// This will tell it that we have done our encryption and there is no more data coming in,
			// and it is now a good time to apply the padding and finalize the encryption process.
			cs.Close ( );

			// Now get the encrypted data from the MemoryStream.
			// Some people make a mistake of using GetBuffer() here, which is not the right way.
			byte[] encryptedData = ms.ToArray ( );

			return encryptedData;
		}

		/// <summary>
		/// 	Encrypt a string into a string using a password
		/// 	Uses Encrypt(byte[], byte[], byte[])
		/// </summary>
		/// <param name = "clearText">The clear text.</param>
		/// <param name = "password">The password.</param>
		/// <returns></returns>
		public static string Encrypt ( this string clearText, string password ) {
			if (string.IsNullOrEmpty ( clearText )) {
				return clearText;
			}

			// First we need to turn the input string into a byte array.
			byte[] clearBytes = Encoding.Unicode.GetBytes ( clearText );

			// Then, we need to turn the password into Key and IV
			// We are using salt to make it harder to guess our key using a dictionary attack -
			// trying to guess a password by enumerating all possible words.
			Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes ( password,
															  new byte[] {
			                                                  	0x49 , 0x76 , 0x61 , 0x6e , 0x20 , 0x4d , 0x65 , 0x64 , 0x76 , 0x65 , 0x64 ,
			                                                  	0x65 , 0x76
			                                                  } );
			// Now get the key/IV and do the encryption using the function that accepts byte arrays.
			// Using PasswordDeriveBytes object we are first getting 32 bytes for the Key
			// (the default Rijndael key length is 256bit = 32bytes) and then 16 bytes for the IV.
			// IV should always be the block size, which is by default 16 bytes (128 bit) for Rijndael.
			// If you are using DES/TripleDES/RC2 the block size is 8 bytes and so should be the IV size.
			// You can also read KeySize/BlockSize properties off the algorithm to find out the sizes.
			byte[] encryptedData = clearBytes.Encrypt ( pdb.GetBytes ( 32 ), pdb.GetBytes ( 16 ) );

			// Now we need to turn the resulting byte array into a string.
			// A common mistake would be to use an Encoding class for that. It does not work
			// because not all byte values can be represented by characters.
			// We are going to be using Base64 encoding that is designed exactly for what we are
			// trying to do.
			return Convert.ToBase64String ( encryptedData );
		}

		///<summary>
		///	Encrypt bytes into bytes using a password
		///	Uses Encrypt(byte[], byte[], byte[])
		///</summary>
		///<param name = "clearData">The clear data.</param>
		///<param name = "password">The password.</param>
		///<returns></returns>
		public static byte[] Encrypt ( this byte[] clearData, string password ) {
			// We need to turn the password into Key and IV.
			// We are using salt to make it harder to guess our key using a dictionary attack -
			// trying to guess a password by enumerating all possible words.
			Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes ( password,
															  new byte[] {
			                                                  	0x49 , 0x76 , 0x61 , 0x6e , 0x20 , 0x4d , 0x65 , 0x64 , 0x76 , 0x65 , 0x64 ,
			                                                  	0x65 , 0x76
			                                                  } );

			// Now get the key/IV and do the encryption using the function that accepts byte arrays.
			// Using PasswordDeriveBytes object we are first getting 32 bytes for the Key
			// (the default Rijndael key length is 256bit = 32bytes) and then 16 bytes for the IV.
			// IV should always be the block size, which is by default 16 bytes (128 bit) for Rijndael.
			// If you are using DES/TripleDES/RC2 the block size is 8 bytes and so should be the IV size.
			// You can also read KeySize/BlockSize properties off the algorithm to find out the sizes.
			return clearData.Encrypt ( pdb.GetBytes ( 32 ), pdb.GetBytes ( 16 ) );
		}

		/// <summary>
		/// 	Encrypts the specified file in.
		/// </summary>
		/// <param name = "fileIn">The file in.</param>
		/// <param name = "fileOut">The file out.</param>
		/// <param name = "password">The password.</param>
		public static void Encrypt ( this FileInfo fileIn, string fileOut, string password ) {
			Encrypt ( fileIn.FullName, fileOut, password );
		}

		/// <summary>
		/// 	Encrypt a file into another file using a password
		/// </summary>
		/// <param name = "fileIn">The file in.</param>
		/// <param name = "fileOut">The file out.</param>
		/// <param name = "password">The password.</param>
		public static void Encrypt ( this String fileIn, string fileOut, string password ) {
			// First we are going to open the file streams
			FileStream fsIn = new FileStream ( fileIn, FileMode.Open, FileAccess.Read );
			FileStream fsOut = new FileStream ( fileOut, FileMode.OpenOrCreate, FileAccess.Write );

			// Then we are going to derive a Key and an IV from the Password and create an algorithm
			Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes ( password,
															  new byte[] {
			                                                  	0x49 , 0x76 , 0x61 , 0x6e , 0x20 , 0x4d , 0x65 , 0x64 , 0x76 , 0x65 , 0x64 ,
			                                                  	0x65 , 0x76
			                                                  } );

			Rijndael alg = Rijndael.Create ( );

			alg.Key = pdb.GetBytes ( 32 );
			alg.IV = pdb.GetBytes ( 16 );

			// Now create a crypto stream through which we are going to be pumping data.
			// Our fileOut is going to be receiving the encrypted bytes.
			CryptoStream cs = new CryptoStream ( fsOut, alg.CreateEncryptor ( ), CryptoStreamMode.Write );

			// Now will will initialize a buffer and will be processing the input file in chunks.
			// This is done to avoid reading the whole file (which can be huge) into memory.
			const int bufferLen = 4096;
			byte[] buffer = new byte[bufferLen];
			int bytesRead;

			do {
				// read a chunk of data from the input file
				bytesRead = fsIn.Read ( buffer, 0, bufferLen );

				// encrypt it
				cs.Write ( buffer, 0, bytesRead );
			} while (bytesRead != 0);

			// close everything
			cs.Close ( ); // this will also close the unrelying fsOut stream
			fsIn.Close ( );
		}

		/// <summary>
		/// 	Decrypt a byte array into a byte array using a key and an IV
		/// </summary>
		/// <param name = "cipherData">The cipher data.</param>
		/// <param name = "key">The key.</param>
		/// <param name = "iv">The iv.</param>
		/// <returns></returns>
		public static byte[] Decrypt ( this byte[] cipherData, byte[] key, byte[] iv ) {
			// Create a MemoryStream that is going to accept the decrypted bytes
			MemoryStream ms = new MemoryStream ( );

			// Create a symmetric algorithm.
			// We are going to use Rijndael because it is strong and available on all platforms.
			// You can use other algorithms, to do so substitute the next line with something like
			//                      TripleDES alg = TripleDES.Create();
			Rijndael alg = Rijndael.Create ( );

			// Now set the key and the IV.
			// We need the IV (Initialization Vector) because the algorithm is operating in its default
			// mode called CBC (Cipher Block Chaining). The IV is XORed with the first block (8 byte)
			// of the data after it is decrypted, and then each decrypted block is XORed with the previous
			// cipher block. This is done to make encryption more secure.
			// There is also a mode called ECB which does not need an IV, but it is much less secure.
			alg.Key = key;
			alg.IV = iv;

			// Create a CryptoStream through which we are going to be pumping our data.
			// CryptoStreamMode.Write means that we are going to be writing data to the stream
			// and the output will be written in the MemoryStream we have provided.
			CryptoStream cs = new CryptoStream ( ms, alg.CreateDecryptor ( ), CryptoStreamMode.Write );

			// Write the data and make it do the decryption
			cs.Write ( cipherData, 0, cipherData.Length );

			// Close the crypto stream (or do FlushFinalBlock).
			// This will tell it that we have done our decryption and there is no more data coming in,
			// and it is now a good time to remove the padding and finalize the decryption process.
			cs.Close ( );

			// Now get the decrypted data from the MemoryStream.
			// Some people make a mistake of using GetBuffer() here, which is not the right way.
			byte[] decryptedData = ms.ToArray ( );

			return decryptedData;
		}

		/// <summary>
		/// 	Decrypt a string into a string using a password
		/// 	Uses Decrypt(byte[], byte[], byte[])
		/// </summary>
		/// <param name = "cipherText">The cipher text.</param>
		/// <param name = "password">The password.</param>
		/// <returns></returns>
		public static string Decrypt ( this string cipherText, string password ) {
			if (string.IsNullOrEmpty ( cipherText )) {
				return cipherText;
			}

			// First we need to turn the input string into a byte array.
			// We presume that Base64 encoding was used
			byte[] cipherBytes = Convert.FromBase64String ( cipherText );

			// Then, we need to turn the password into Key and IV
			// We are using salt to make it harder to guess our key using a dictionary attack -
			// trying to guess a password by enumerating all possible words.
			Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes ( password,
															  new byte[] {
			                                                  	0x49 , 0x76 , 0x61 , 0x6e , 0x20 , 0x4d , 0x65 , 0x64 , 0x76 , 0x65 , 0x64 ,
			                                                  	0x65 , 0x76
			                                                  } );

			// Now get the key/IV and do the decryption using the function that accepts byte arrays.
			// Using PasswordDeriveBytes object we are first getting 32 bytes for the Key
			// (the default Rijndael key length is 256bit = 32bytes) and then 16 bytes for the IV.
			// IV should always be the block size, which is by default 16 bytes (128 bit) for Rijndael.
			// If you are using DES/TripleDES/RC2 the block size is 8 bytes and so should be the IV size.
			// You can also read KeySize/BlockSize properties off the algorithm to find out the sizes.
			byte[] decryptedData = Decrypt ( cipherBytes, pdb.GetBytes ( 32 ), pdb.GetBytes ( 16 ) );

			// Now we need to turn the resulting byte array into a string.
			// A common mistake would be to use an Encoding class for that. It does not work
			// because not all byte values can be represented by characters.
			// We are going to be using Base64 encoding that is designed exactly for what we are
			// trying to do.
			return Encoding.Unicode.GetString ( decryptedData );
		}

		/// <summary>
		/// 	Decrypt bytes into bytes using a password
		/// 	Uses Decrypt(byte[], byte[], byte[])
		/// </summary>
		/// <param name = "cipherData">The cipher data.</param>
		/// <param name = "password">The password.</param>
		/// <returns></returns>
		public static byte[] Decrypt ( this byte[] cipherData, string password ) {
			// We need to turn the password into Key and IV.
			// We are using salt to make it harder to guess our key using a dictionary attack -
			// trying to guess a password by enumerating all possible words.
			Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes ( password,
															  new byte[] {
			                                                  	0x49 , 0x76 , 0x61 , 0x6e , 0x20 , 0x4d , 0x65 , 0x64 , 0x76 , 0x65 , 0x64 ,
			                                                  	0x65 , 0x76
			                                                  } );

			// Now get the key/IV and do the Decryption using the function that accepts byte arrays.
			// Using PasswordDeriveBytes object we are first getting 32 bytes for the Key
			// (the default Rijndael key length is 256bit = 32bytes) and then 16 bytes for the IV.
			// IV should always be the block size, which is by default 16 bytes (128 bit) for Rijndael.
			// If you are using DES/TripleDES/RC2 the block size is 8 bytes and so should be the IV size.
			// You can also read KeySize/BlockSize properties off the algorithm to find out the sizes.
			return cipherData.Decrypt ( pdb.GetBytes ( 32 ), pdb.GetBytes ( 16 ) );
		}

		/// <summary>
		/// 	Decrypts the specified file in.
		/// </summary>
		/// <param name = "fileIn">The file in.</param>
		/// <param name = "fileOut">The file out.</param>
		/// <param name = "password">The password.</param>
		public static void Decrypt ( this FileInfo fileIn, string fileOut, string password ) {
			Decrypt ( fileIn.FullName, fileOut, password );
		}

		/// <summary>
		/// 	Decrypt a file into another file using a password
		/// </summary>
		/// <param name = "fileIn">The file in.</param>
		/// <param name = "fileOut">The file out.</param>
		/// <param name = "password">The password.</param>
		public static void Decrypt ( this String fileIn, string fileOut, string password ) {
			// First we are going to open the file streams
			FileStream fsIn = new FileStream ( fileIn, FileMode.Open, FileAccess.Read );
			FileStream fsOut = new FileStream ( fileOut, FileMode.OpenOrCreate, FileAccess.Write );

			// Then we are going to derive a Key and an IV from the Password and create an algorithm
			Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes ( password,
															  new byte[] {
			                                                  	0x49 , 0x76 , 0x61 , 0x6e , 0x20 , 0x4d , 0x65 , 0x64 , 0x76 , 0x65 , 0x64 ,
			                                                  	0x65 , 0x76
			                                                  } );

			Rijndael alg = Rijndael.Create ( );

			alg.Key = pdb.GetBytes ( 32 );
			alg.IV = pdb.GetBytes ( 16 );

			// Now create a crypto stream through which we are going to be pumping data.
			// Our fileOut is going to be receiving the Decrypted bytes.
			CryptoStream cs = new CryptoStream ( fsOut, alg.CreateDecryptor ( ), CryptoStreamMode.Write );

			// Now will will initialize a buffer and will be processing the input file in chunks.
			// This is done to avoid reading the whole file (which can be huge) into memory.
			const int bufferLen = 4096;
			byte[] buffer = new byte[bufferLen];
			int bytesRead;

			do {
				// read a chunk of data from the input file
				bytesRead = fsIn.Read ( buffer, 0, bufferLen );

				// Decrypt it
				cs.Write ( buffer, 0, bytesRead );
			} while (bytesRead != 0);

			// close everything
			cs.Close ( ); // this will also close the unrelying fsOut stream
			fsIn.Close ( );
		}

		//TODO: DA TESTARE
		///// <summary>
		///// 	Toes the dictionary.
		///// </summary>
		///// <param name = "s">The s.</param>
		///// <param name = "separator">The separator.</param>
		///// <returns></returns>
		//public static Dictionary<string, string> ToDictionary(this string s, string separator)
		//{
		//    NameValueCollection values = s.ToNameValueCollection(separator);
		//    return values.AllKeys.ToDictionary(str => str, str => values[str]);
		//}
		///// <summary>
		///// 	Toes the name value collection.
		///// </summary>
		///// <param name = "s">The s.</param>
		///// <param name = "separator">The separator.</param>
		///// <returns></returns>
		//public static NameValueCollection ToNameValueCollection(this string s, string separator)
		//{
		//    if (string.IsNullOrEmpty(separator))
		//        throw new ArgumentNullException("separator");
		//    NameValueCollection values = new NameValueCollection();
		//    foreach (string str in s.Split(separator.ToCharArray()))
		//    {
		//        string[] strArray2 = str.Split("=".ToCharArray());
		//        string name = strArray2[0].Trim();
		//        string str3 = (strArray2.Length > 1) ? strArray2[1].Trim() : string.Empty;
		//        if (name.Length > 0)
		//            values.Add(name, str3);
		//    }
		//    return values;
		//}
	}
}
